<!DOCTYPE html>
<html>
  <head>
    <title>Windows客户端</title>
  </head>
  <body>
    <h3>Mac直播流接收(需要用户主动点击视频区域，才能播放)</h3>
    <!-- 强制设置视频类型为object-fit: contain，避免画面被隐藏 -->
    <video
      id="remoteVideo"
      autoplay
      playsinline
      width="640"
      height="480"
      style="object-fit: contain; border: 1px solid #000"
      onclick="this.play().catch(e => console.log('播放失败:', e))"
    ></video>
    <p id="status">连接中...</p>
    <p id="streamInfo">流信息：未接收</p>

    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io();
      const remoteVideo = document.getElementById("remoteVideo");
      const status = document.getElementById("status");
      const streamInfo = document.getElementById("streamInfo");
      let peerConnection;

      function init() {
        console.log("客户端初始化，注册为观众");
        socket.emit("viewer");
      }

      socket.on("signal", async (data) => {
        console.log("收到信令:", data);
        const { from: broadcasterId, type, sdp, candidate } = data;
        if (data.type === "ice") {
          console.log("收到ICE候选:", candidate.type, candidate.address);
        }

        if (!peerConnection) {
          console.log("初始化PeerConnection");
          peerConnection = new RTCPeerConnection({
            iceServers: [
              // Cloudflare STUN（稳定性高，解析成功率高）
              { urls: "stun:stun.cloudflare.com:3478" },
              { urls: "stun:stun.cloudflare.com:5349" },
              // 阿里云STUN（国内网络友好）
              { urls: "stun:stun.aliyun.com:3478" },
              // 腾讯云STUN（国内网络友好）
              { urls: "stun:stun.qcloud.com:3478" },
              // 若仍解析失败，直接使用IP地址（需提前确认IP是否有效）
              { urls: "stun:104.16.111.25:3478" }, //
            ],
            iceTransportPolicy: "all", // 允许所有类型候选（host/srflx/relay）
            iceCandidatePoolSize: 10, // 预收集候选，加速连接
            iceConnectionTimeout: 20000,
            iceKeepaliveInterval: 25000, // 每25秒发送一次保活包（默认5秒，可适当延长）
          });

          // 关键：详细检查媒体流信息
          peerConnection.ontrack = (event) => {
            console.log("触发ontrack事件，收到媒体流");
            const stream = event.streams[0];
            const track = event.track;

            // 打印流信息到控制台
            console.log("流ID:", stream.id);
            console.log("视频轨道:", stream.getVideoTracks().length);
            console.log("音频轨道:", stream.getAudioTracks().length);
            console.log("轨道状态:", stream.getVideoTracks()[0]?.readyState);
            track.onmute = () => {
              console.warn("远程轨道被静音");
              status.textContent = "直播流已静音";
              if (track.readyState === "live") {
                track.muted = false;
              }
            };
            track.onunmute = () => {
              console.log("远程轨道已启用");
              status.textContent = "已接收直播流";
            };
            track.onended = () => {
              console.error("远程轨道已结束");
              status.textContent = "直播流已结束";
            };
            // 显示流信息到页面
            streamInfo.textContent = `流信息：视频轨道=${
              stream.getVideoTracks().length
            }，状态=${stream.getVideoTracks()[0]?.readyState || "无"}`;

            // 强制设置视频源并触发播放
            if (remoteVideo.srcObject !== stream) {
              remoteVideo.srcObject = stream;
              // 主动触发播放（解决部分浏览器自动播放限制）
              remoteVideo.play().catch((err) => {
                console.error("播放失败，可能需要用户交互:", err);
                status.textContent = "需要点击视频以播放（浏览器限制）";
              });
            }

            status.textContent = "已接收直播流";
          };

          peerConnection.oniceconnectionstatechange = () => {
            console.log("ICE连接状态:", peerConnection.iceConnectionState);
            status.textContent = `连接状态: ${peerConnection.iceConnectionState}`;
            // 连接失败时尝试重连
            if (peerConnection.iceConnectionState === "failed") {
              peerConnection.restartIce();
            }
          };

          peerConnection.onicecandidate = (event) => {
            if (event.candidate) {
              const { type, address } = event.candidate;
              console.log(`原始本地ICE候选：类型=${type}，地址=${address}`);

              // 定义有效私网IP范围（IPv4）
              const isValidPrivateIpv4 = (ip) => {
                const parts = ip.split(".").map(Number);
                // 10.x.x.x 或 192.168.x.x 或 172.16.x.x-172.31.x.x
                return (
                  parts[0] === 10 ||
                  (parts[0] === 192 && parts[1] === 168) ||
                  (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31)
                );
              };

              // 过滤规则：仅保留有效私网IPv4、有效IPv6（可选）、srflx（公网反射）、relay（中继）
              let shouldSend = false;
              if (type === "host") {
                // 对host类型严格过滤
                if (address.includes(":")) {
                  // IPv6：若网络支持IPv6可保留，否则过滤（根据实际环境调整）
                  shouldSend = true; // 暂时保留，若后续发现IPv6无效可改为false
                } else {
                  // IPv4：仅保留有效私网IP
                  shouldSend = isValidPrivateIpv4(address);
                }
              } else {
                // 非host类型（srflx/relay）通常是通过STUN/TURN获取的，保留
                shouldSend = true;
              }

              if (shouldSend) {
                console.log(`发送有效ICE候选：类型=${type}，地址=${address}`);
                socket.emit("signal", {
                  target: broadcasterId,
                  type: "ice",
                  candidate: event.candidate,
                });
              } else {
                console.warn(`过滤无效ICE候选：类型=${type}，地址=${address}`);
              }
            }
          };
        }

        try {
          if (type === "offer") {
            await peerConnection.setRemoteDescription(
              new RTCSessionDescription(sdp)
            );
            const answer = await peerConnection.createAnswer();
            await peerConnection.setLocalDescription(answer);
            socket.emit("signal", {
              target: broadcasterId,
              type: "answer",
              sdp: answer,
            });
          } else if (type === "ice") {
            await peerConnection.addIceCandidate(
              new RTCIceCandidate(candidate)
            );
          }
        } catch (err) {
          console.error("信令处理错误:", err);
          status.textContent = `错误: ${err.message}`;
        }
      });

      // 视频元素错误监听强化
      remoteVideo.addEventListener("error", (e) => {
        console.error("视频错误详情:", e.target.error);
        const errors = {
          3: "解码失败（可能是编码器不兼容）",
          4: "视频格式不支持",
        };
        status.textContent = `视频错误: ${
          errors[e.target.error.code] || "未知错误"
        }`;
      });

      // 监听视频播放状态
      remoteVideo.addEventListener("playing", () =>
        console.log("视频开始播放")
      );
      remoteVideo.addEventListener("pause", () => console.log("视频暂停"));
      remoteVideo.addEventListener("waiting", () => console.log("视频缓冲中"));

      socket.on("broadcaster-disconnected", () => {
        status.textContent = "主播已断开";
        remoteVideo.srcObject = null;
        if (peerConnection) {
          peerConnection.close();
          peerConnection = null;
        }
      });

      socket.on("connect", () => {
        console.log("信令通道已连接，socket ID:", socket.id);
        status.textContent = "信令通道已连接";
      });

      socket.on("disconnect", (data) => {
        console.error("Websocket断开:", data);
        status.textContent = `Websocket断开: ${data}`;
        // 若因服务器重启断开，自动重连
        if (reason === "io server disconnect") {
          socket.connect();
        }
      });

      socket.on("reconnect", (attempt) => {
        console.log(`信令通道重连成功（第${attempt}次尝试）`);
        status.textContent = "信令通道已重连，正在恢复直播...";
        // 重连后重新注册为观众，触发新的ICE协商
        if (!peerConnection) {
          socket.emit("viewer");
        }
      });
      window.onload = init;
      // window.addEventListener("message", (event) => {
      //   if(event.data==='window-ready'){
      //     init();
      //   }
      // })
    </script>
  </body>
</html>
